package com.iplant.basic.serviceImpl.dao;

import com.iplant.base.po.BasePO;
import com.iplant.base.po.OutResult;
import com.iplant.base.po.Pagination;
import com.iplant.base.po.enums.ExceptionTypes;
import com.iplant.base.utils.serializer.CloneTool;
import com.iplant.base.utils.general.StringUtils;
import com.iplant.base.utils.sql.BaseDAO;
import com.iplant.base.utils.sql.orm.ORMUtils;
import com.iplant.base.utils.sql.orm.PoService;
import com.iplant.basic.service.basicenum.bfc.BFCMessageStatus;
import com.iplant.basic.service.basicenum.bfc.BFCMessageType;
import com.iplant.basic.service.po.bfc.BFCMessage;
import com.iplant.basic.service.po.bms.BMSEmployee;
import com.iplant.basic.service.po.bpm.BPMTaskBase;
import com.iplant.basic.serviceImpl.dao.bfc.BFCMessageDAO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author xiuto
 */
public abstract class TaskBaseDao<T extends BPMTaskBase> extends BaseDAO {
    private static Logger logger = LoggerFactory.getLogger(TaskBaseDao.class);

    private static Map<String, TaskBaseDao<? extends BasePO>> InstanceMap = new HashMap<>();

    public static TaskBaseDao<? extends BasePO> GetInstance(String wIndexName) {
        if (InstanceMap == null || StringUtils.isEmpty(wIndexName) || !InstanceMap.containsKey(wIndexName)) {
            return null;
        }
        return InstanceMap.get(wIndexName);
    }



    private Class<T> GetTClass(){
        return (Class<T>)Clazz;
    }



    public TaskBaseDao(Class<T> wClazz) {
        super(wClazz);
        this.Initialize();
    }


    /**
     * 初始化并设置缓存
     *
     * @param wT1
     * @param <T1>
     */
    protected <T1 extends TaskBaseDao<T>> void SetInstance(T1 wT1) {

        if (Clazz != null && !InstanceMap.containsKey(wT1.getIndexName(Clazz))) {
            InstanceMap.put(wT1.getIndexName(Clazz), wT1);
        }
    }


    /**
     * 初始化
     */
    protected abstract void Initialize();

    public List<T> BFC_GetUndoTaskList(
            BMSEmployee wLoginUser, int wResponsorID, List<Integer> wEventIDs, Map<String, Object> wParams,
            Pagination wPagination,
            OutResult<Integer> wErrorCode) {

        List<T> wResult = new ArrayList<T>();
        try {
            // 获取所有任务消息
            if (wResponsorID <= 0) {
                wResponsorID = wLoginUser.getID();
            }
            if (wResponsorID <= 0) {
                return wResult;
            }
            if (wEventIDs == null || wEventIDs.size() == 0) {
                return wResult;
            }
            wEventIDs.removeIf(p -> p <= 0);
            if (wEventIDs.size() == 0) {
                return wResult;
            }
            List<BFCMessage> wMessageList = BFCMessageDAO.getInstance().BFC_GetUndoMessageList(wLoginUser, wResponsorID,
                    wEventIDs, -1, -1, null, null, Pagination.getMaxSize(), wErrorCode);

            List<Integer> wTaskIDList = wMessageList.stream().map(p -> (int) p.MessageID).distinct().collect(
                    Collectors.toList());

            List<T> wTaskList = this.BFC_GetTaskList(wLoginUser, wTaskIDList, wParams, wPagination, wErrorCode);

            wTaskList.removeIf(p -> p.Status <= 0);

            if (wTaskList.size() > 0) {

                Field[] fields = GetTClass().getFields();
                Field wStepField = null;
                Field wStatusField = null;
                for (Field field : fields) {
                    if (field.getName().equals("StepID")) {

                        if (field.getType() == Integer.class || field.getType() == int.class ||
                                field.getType() == Long.class || field.getType() == long.class) {
                            wStepField = field;
                        }
                    }
                    if (field.getName().equals("Status")) {

                        if (field.getType() == Integer.class || field.getType() == int.class ||
                                field.getType() == Long.class || field.getType() == long.class) {
                            wStatusField = field;
                        }
                    }
                }

                if (wStepField != null) {
                    Map<Integer, T> wTaskMap = wTaskList.stream().collect(Collectors.toMap(p -> p.ID, p -> p));

                    T wTaskTemp = null;
                    for (BFCMessage wBFCMessage : wMessageList) {
                        if (!wTaskMap.containsKey((int) wBFCMessage.MessageID)) {
                            continue;
                        }

                        wTaskTemp = CloneTool.Clone(wTaskMap.get((int) wBFCMessage.MessageID), GetTClass());
                        wStepField.set(wTaskTemp, wBFCMessage.StepID);
                        wResult.add(wTaskTemp);
                    }
                }
                // 剔除任务状态为0的任务（废弃任务）
                Field wStatusField1 = wStatusField;
                if (wStatusField1 != null) {
                    wResult = wResult.stream().filter(p -> {
                        try {
                            return StringUtils.parseInt(wStatusField1.get(p)) != 0;
                        } catch (IllegalAccessException e) {
                            logger.error("BFC_GetUndoTaskList filter", e);
                        }
                        return false;
                    }).collect(Collectors.toList());

                }
            }
        } catch (Exception e) {
            wErrorCode.set(ExceptionTypes.Exception.getValue());
            logger.error("BFC_GetUndoTaskList", e);
        }
        return wResult;

    }

    public List<T> BFC_GetDoneTaskList(
            BMSEmployee wLoginUser, int wResponsorID, List<Integer> wEventIDs, Calendar wStartTime, Calendar wEndTime
            , Map<String, Object> wParams,
            Pagination wPagination, OutResult<Integer> wErrorCode) {
        List<T> wResult = new ArrayList<T>();
        try {
            // 获取所有任务消息
            if (wResponsorID <= 0) {
                wResponsorID = wLoginUser.getID();
            }
            if (wResponsorID <= 0) {
                return wResult;
            }
            if (wEventIDs == null || wEventIDs.size() == 0) {
                return wResult;
            }
            wEventIDs.removeIf(p -> p <= 0);
            if (wEventIDs.size() == 0) {
                return wResult;
            }
            List<BFCMessage> wMessageList = BFCMessageDAO.getInstance().BFC_GetDoneMessageList(wLoginUser, wResponsorID,
                    wEventIDs, -1, -1, wStartTime, wEndTime, Pagination.getMaxSize(), wErrorCode);

            List<Integer> wTaskIDList = wMessageList.stream().map(p -> (int) p.MessageID).distinct().collect(
                    Collectors.toList());

            List<T> wTaskList = this.BFC_GetTaskList(wLoginUser, wTaskIDList, wParams, wPagination, wErrorCode);

            wTaskList.removeIf(p -> p.Active <= 0);

            if (wTaskList.size() > 0) {
                Field[] fields = GetTClass().getFields();
                Field wStepField = null;
                Field wStatusField = null;
                for (Field field : fields) {
                    if (field.getName().equals("StepID")) {

                        if (field.getType() == Integer.class || field.getType() == int.class ||
                                field.getType() == Long.class || field.getType() == long.class) {
                            wStepField = field;
                        }
                    }
                    if (field.getName().equals("Status")) {

                        if (field.getType() == Integer.class || field.getType() == int.class ||
                                field.getType() == Long.class || field.getType() == long.class) {
                            wStatusField = field;
                        }
                    }
                }

                if (wStepField != null) {
                    Map<Integer, T> wTaskMap = wTaskList.stream().collect(Collectors.toMap(p -> p.ID, p -> p));

                    T wTaskTemp = null;
                    for (BFCMessage wBFCMessage : wMessageList) {
                        if (!wTaskMap.containsKey((int) wBFCMessage.MessageID)) {
                            continue;
                        }

                        wTaskTemp = CloneTool.Clone(wTaskMap.get((int) wBFCMessage.MessageID), GetTClass());
                        wStepField.set(wTaskTemp, wBFCMessage.StepID);
                        wResult.add(wTaskTemp);
                    }
                }
                Field wStatusField1 = wStatusField;
                // 剔除任务状态为0的任务（废弃任务）
                if (wStatusField1 != null) {
                    wResult = wResult.stream().filter(p -> {
                        try {
                            return StringUtils.parseInt(wStatusField1.get(p)) != 0;
                        } catch (IllegalAccessException e) {
                            logger.error("BFC_GetDoneTaskList filter", e);
                        }
                        return false;
                    }).collect(Collectors.toList());

                }
            }


        } catch (Exception e) {
            wErrorCode.set(ExceptionTypes.Exception.getValue());
            logger.error("BFC_GetDoneTaskList", e);
        }
        return wResult;

    }

    /**
     * 获取发起的任务列表
     *
     * @param wLoginUser
     * @param wCreatorID
     * @param wEventIDs
     * @param wStartTime
     * @param wEndTime
     * @param wPagination
     * @param wErrorCode
     * @return
     */
    public List<T> BFC_GetLaunchTaskList(
            BMSEmployee wLoginUser, int wCreatorID, List<Integer> wEventIDs, Calendar wStartTime, Calendar wEndTime,
            Map<String, Object> wParams,
            Pagination wPagination, OutResult<Integer> wErrorCode) {
        List<T> wResult = null;
        try {
            wParams.put("UpFlowID", wCreatorID);
            wParams.put("CStartTime", wStartTime);
            wParams.put("DEndTime", wEndTime);
            wResult = this.SelectPOList(wLoginUser, wParams, wPagination, wErrorCode);
        } catch (Exception ex) {
            logger.error("BFC_GetLaunchTaskList", ex);
        }
        return wResult;
    }

    public List<T> BFC_GetSendTaskList(
            BMSEmployee wLoginUser, int wResponsorID, List<Integer> wEventIDs, Calendar wStartTime, Calendar wEndTime
            , Map<String, Object> wParams,
            Pagination wPagination, OutResult<Integer> wErrorCode) {

        List<T> wResult = new ArrayList<T>();
        try {
            if (wResponsorID <= 0) {
                wResponsorID = wLoginUser.getID();
            }
            if (wResponsorID <= 0) {
                return wResult;
            }
            if (wEventIDs == null || wEventIDs.size() == 0) {
                return wResult;
            }
            wEventIDs.removeIf(p -> p <= 0);
            if (wEventIDs.size() == 0) {
                return wResult;
            }

            List<T> wTaskList = this.BFC_GetLaunchTaskList(wLoginUser, wResponsorID, wEventIDs, wStartTime, wEndTime,
                    wParams,
                    wPagination, wErrorCode);

            wTaskList.removeIf(p -> p.Active <= 0);

            if (wTaskList.size() > 0) {

                Field[] fields = GetTClass().getFields();
                Field wStatusField = null;
                for (Field field : fields) {

                    if (field.getName().equals("Status")) {

                        if (field.getType() == Integer.class || field.getType() == int.class ||
                                field.getType() == Long.class || field.getType() == long.class) {
                            wStatusField = field;
                        }
                    }
                }
                Field wStatusField1 = wStatusField;

                // 剔除任务状态为0的任务（废弃任务）
                if (wStatusField1 != null) {
                    wTaskList = wTaskList.stream().filter(p -> {
                        try {
                            return StringUtils.parseInt(wStatusField1.get(p)) != 0;
                        } catch (IllegalAccessException e) {
                            logger.error("BFC_GetSendTaskList filter", e);
                        }
                        return false;
                    }).collect(Collectors.toList());

                }
            }
            wResult = wTaskList;
        } catch (Exception e) {
            wErrorCode.set(ExceptionTypes.Exception.getValue());
            logger.error("BFC_GetSendTaskList", e);
        }
        return wResult;

    }


    public List<T> BFC_UpdateTaskList(
            BMSEmployee wLoginUser, List<Map> wTList, Integer wModuleID, Integer wStepID, int wStatus,Calendar wMin,Calendar wMax,
            OutResult<Integer> wErrorCode) {
        List<T> wTaskList = new ArrayList<>();
        try {
            if (wTList == null || wTList.size() == 0) {
                return wTaskList;
            }

            wTaskList = CloneTool.CloneArray(wTList, GetTClass());


            if (wStatus == BFCMessageStatus.Finished.getValue()) {
                BFCMessageDAO.getInstance().BFC_HandleTaskMessage(wLoginUser, wLoginUser.getID(),
                        wTaskList.stream().map(p -> p.ID).distinct().collect(Collectors.toList()), wModuleID, wStepID,
                        BFCMessageStatus.Finished.getValue(), 1,wMin,wMax, wErrorCode);
            }
            if (wStatus == BFCMessageStatus.Close.getValue()) {
                BFCMessageDAO.getInstance().BFC_HandleMessage(wLoginUser, wLoginUser.getID(), wTaskList.stream().map(
                                p -> p.ID).distinct().collect(Collectors.toList()), StringUtils.parseListArgs(wStepID),
                        wModuleID, BFCMessageType.Task.getValue(), BFCMessageStatus.Close.getValue(),wMin,wMax, wErrorCode);
            }
            //wStatus 是完成 取消 还是撤回由业务判断


            if (wErrorCode.Result != 0) {
                return wTaskList;
            }

            this.BFC_UpdateTaskList(wLoginUser, wTaskList, wErrorCode);
        } catch (Exception ex) {
            wErrorCode.set(ExceptionTypes.Exception.getValue());
            logger.error("BFC_UpdateTaskList", ex);
        }
        return wTaskList;

    }

    /**
     * 任务提交
     *
     * @param wLoginUser
     * @param wTList
     * @param wErrorCode
     */
    public void BFC_UpdateTaskList(BMSEmployee wLoginUser, List<T> wTList, OutResult<Integer> wErrorCode) {
        try {
            this.UpdatePoList(wLoginUser, wTList, wErrorCode);
        } catch (Exception ex) {
            logger.error("BFC_UpdateTaskList", ex);
        }
    }


    /**
     * 获取单条任务
     *
     * @param wLoginUser 用户
     * @param wID        任务ID
     * @param wCode      任务编号
     * @param wErrorCode 错误码
     * @return 任务
     */
    public T BFC_GetTaskInfo(BMSEmployee wLoginUser, int wID, String wCode, OutResult<Integer> wErrorCode) {
        T wResult = null;
        try {
            Map<String, Object> wParams = new HashMap<String, Object>();
            wParams.put("ID", wID);
            wParams.put("Code", wCode);
            wResult = this.SelectPO(wLoginUser, wParams, wErrorCode);
        } catch (Exception ex) {
            logger.error("BFC_GetTaskInfo", ex);
        }
        return wResult;
    }

    /**
     * 根据任务ID列表获取任务
     *
     * @param wLoginUser 用户
     * @param wTaskIDs   任务ID列表
     * @param wErrorCode 错误码
     * @return 任务列表
     */
    public List<T> BFC_GetTaskList(
            BMSEmployee wLoginUser, List<Integer> wTaskIDs, Map<String, Object> wParams, Pagination wPagination,
            OutResult<Integer> wErrorCode) {
        List<T> wResult = null;
        try {
            wResult = this.SelectPOList(wLoginUser, wTaskIDs,  wParams, GetTClass(), wPagination, wErrorCode);
        } catch (Exception ex) {
            logger.error("BFC_GetTaskList", ex);
        }
        return wResult;
    }

}
